﻿/*----------------------------------------------------------------
//  <copyright file="EntityManager.cs" company="MicroCloud@151504200868">
//      Copyright © 2020-2024 MicroCloud Corporation, All rights reserved.
//  </copyright>
//  <site>https://gitee.com/chenmm123/microclouds</site>
//  <last-editor>cmm</last-editor>
//  <last-date>2023-12-06 09:27</last-date>
//----------------------------------------------------------------*/

namespace MicroCloud.Entity
{
    #region "实体管理器"
    /// <summary>
    /// 实体管理器
    /// </summary>
    public class EntityManager : IEntityManager
    {
        //字段
        private IEntityRegister[] entityRegisters = Array.Empty<IEntityRegister>();
        private readonly ConcurrentDictionary<Type, IEntityRegister[]> _entityRegisterDict = new();
        private readonly ILogger _logger;

        private bool _initialized;

        #region "构造函数"
        #region "初始化一个实体管理器的新实例"
        /// <summary>
        /// 初始化一个实体管理器 <see cref="EntityManager"/> 的新实例
        /// </summary>
        /// <param name="provider">服务提供者</param>
        public EntityManager(IServiceProvider provider)
        {
            _logger = provider.GetLogger<EntityManager>();
        }
        #endregion

        #endregion

        #region "方法"
        #region "初始化实体类型注册"
        /// <summary>
        /// 初始化实体类型注册
        /// </summary>
        public virtual void Initialize()
        {
            if (_initialized)
            {
                _logger.LogDebug("实体管理器已完成初始化，跳过。");
                return;
            }
            var dict = _entityRegisterDict;
            Type[] types = AssemblyManager.FindTypesByBase<IEntityRegister>() ?? Array.Empty<Type>();
            if (!(types?.Length > 0))
            {
                _logger.LogDebug("实体类型集合为空，跳过。");
                return;
            }
            //创建实体映射类的实例
            entityRegisters = types.Select(type => Activator.CreateInstance(type) as IEntityRegister).Where(w => w.Enabled).ToArray();
            List<IGrouping<Type, IEntityRegister>> groups = entityRegisters.GroupBy(m => m.DbContextType).ToList();
            Type key;
            dict.Clear();
            foreach (IGrouping<Type, IEntityRegister> group in groups)
            {
                key = group.Key ?? typeof(DefaultDbContext);
                List<IEntityRegister> list = dict.TryGetValue(key, out IEntityRegister[] value) ? value.ToList() : new List<IEntityRegister>();
                list.AddRange(group);
                dict[key] = list.ToArray();
            }

            ////这吊方法不好使，NND，注释掉
            ////添加框架的一些默认实体的实体映射信息(如果不存在)
            //key = typeof(DefaultDbContext);
            //if (dict.ContainsKey(key))
            //{
            //    List<IEntityRegister> list = dict[key].ToList();
            //    list.AddIfNotExist(new EntityInfoConfiguration(), m => m.EntityType.IsBaseOn<IEntityInfo>());
            //    list.AddIfNotExist(new FunctionConfiguration(), m => m.EntityType.IsBaseOn<IFunction>());
            //    dict[key] = list.ToArray();
            //}

            foreach (KeyValuePair<Type, IEntityRegister[]> item in dict)
            {
                foreach (IEntityRegister register in item.Value)
                {
                    _logger.LogDebug("数据上下文 {key} 添加实体类型 {entityType} ", item.Key, register.EntityType);
                }
                _logger.LogInformation("数据上下文 {key} 添加了 {length} 个实体", item.Key, item.Value.Length);
            }

            _initialized = true;
        }
        #endregion
        #region "获取指定上下文类型的实体配置注册信息"
        /// <summary>
        /// 获取指定上下文类型的实体配置注册信息
        /// </summary>
        /// <param name="dbContextType">数据上下文类型</param>
        /// <returns></returns>
        public virtual IEntityRegister[] GetEntityRegisters(Type dbContextType)
        {
            if (!_initialized)
            {
                throw new Exception(I18N.T("数据访问模块未初始化，请确认数据上下文配置节点 MicroCloud:DbContexts 与要使用的数据库类型是否匹配"));
            }
            return _entityRegisterDict.TryGetValue(dbContextType, out IEntityRegister[] value) ? value : Array.Empty<IEntityRegister>();
        }
        #endregion
        #region "获取实体类所属的数据上下文类型"
        /// <summary>
        /// 获取实体类所属的数据上下文类型
        /// </summary>
        /// <param name="entityType">实体类型</param>
        /// <returns>数据上下文类型</returns>
        public virtual Type GetDbContextTypeForEntity(Type entityType)
        {
            if (!_initialized)
            {
                throw new Exception(I18N.T("数据访问模块未初始化，请确认数据上下文配置节点 MicroCloud:DbContexts 与要使用的数据库类型是否匹配。"));
            }
            var dict = _entityRegisterDict;
            if (dict.IsEmpty)
            {
                throw new Exception(I18N.T("未发现任何数据上下文实体映射配置，请通过对各个实体继承基类“EntityTypeConfigurationBase<TEntity, TKey>”以使实体加载到上下文中。"));
            }

            foreach (var item in _entityRegisterDict)
            {
                if (item.Value.Any(m => m.EntityType == entityType))
                {
                    _logger.LogDebug("由实体类 {entityType} 获取到所属上下文类型 {key}", entityType, item.Key);
                    return item.Key;
                }
            }

            throw new Exception(I18N.T("无法获取实体类 {0} 的所属上下文类型，请通过继承基类“EntityTypeConfigurationBase<TEntity, TKey>”配置实体加载到上下文中。", entityType));
        }
        #endregion
        #region "获取已注册实体类型集合"
        /// <summary>
        /// 获取已注册实体类型集合
        /// </summary>
        /// <param name="predicate">条件过滤表达式</param>
        /// <returns>实体类型集合</returns>
        /// <exception cref="Exception"></exception>
        public virtual Type[] GetEntityTypes(Func<Type, bool> predicate = null)
        {
            if (!_initialized)
            {
                throw new Exception(I18N.T("数据访问模块未初始化，请确认数据上下文配置节点 MicroCloud:DbContexts 与要使用的数据库类型是否匹配。"));
            }
            predicate ??= p => true;
            var types = entityRegisters?.Select(o => o.EntityType)?.Where(predicate)?.ToArray();
            return types ?? Array.Empty<Type>();
        }
        #endregion

        #endregion

    }
    #endregion

}
